import { _decorator, Node, director, find, Camera } from 'cc';
import { GameCore } from '../../Base/Class';
import { Constructor, getClassName, NewClass, setClassName } from '../../Base/Global';
import { IGameSystem } from '../../Interfaces/IGameSystem';
import { UILayer } from './base/IUILevel';
import { UIData } from './base/UIData';
import { UIWindow } from './UIWindow';



export class UIManager extends GameCore.ClassBase implements IGameSystem.IAwakeSystem, IGameSystem.IUpdateSystem {
    private updateUIList : Array<IGameSystem.IUpdateSystem> = new Array<IGameSystem.IUpdateSystem>();  // IUpdateSystem 接口
    private waitDoSecondOnLoadList : Array<IGameSystem.ISecondLoad> = new Array<IGameSystem.ISecondLoad>();  // ISecondLoad 接口
    private curDoSecondOnLoadList : Array<IGameSystem.ISecondLoad> = new Array<IGameSystem.ISecondLoad>();  // ISecondLoad 接口
    private requestUIAssetList : Array<UIWindow> = new Array<UIWindow>(); // 资源加载完成回调缓存
    private uiMap = new Map<string, UIWindow>();  // 所有的UI管理
    private uiLayerNodeMap = new Map<UILayer, Node>();
    private uiRootNode : Node = null;
    public get UIRoot():Node { return this.uiRootNode; }
    private uiCamera : Camera = null;
    public get UICamera() : Camera {return this.uiCamera; }

    Awake(): void 
    {
       this.uiRootNode = find("MainCanvas");
       this.uiCamera = this.uiRootNode.getComponentInChildren(Camera);
       this.uiLayerNodeMap.set(UILayer.eLowLayer, this.uiRootNode.getChildByPath("oLowLayer"));
       this.uiLayerNodeMap.set(UILayer.eMidLayer, this.uiRootNode.getChildByPath("oMidLayer"));
       this.uiLayerNodeMap.set(UILayer.eTopLayer, this.uiRootNode.getChildByPath("oTopLayer"));
       director.addPersistRootNode(this.uiRootNode);
    }

    public Update(): void 
    {
        this.updateUIList.forEach((iUpdate)=>{
            iUpdate.Update();
        });

        this.curDoSecondOnLoadList.forEach((imp)=>{
            imp.OnSecondLoad();
            this.TryToAttachToUpdate(imp as unknown as UIWindow);
        });
        this.curDoSecondOnLoadList.slice();

        while(this.requestUIAssetList.length > 0)
        {
            var oUI = this.requestUIAssetList.shift();
            if(this.uiMap.has(oUI.className))
            {
                oUI.RequestAsset();
            }
        }

        if(this.waitDoSecondOnLoadList.length > 0){
            this.curDoSecondOnLoadList = this.curDoSecondOnLoadList.concat(this.waitDoSecondOnLoadList);
            this.waitDoSecondOnLoadList.slice();
        }
    }

    private TryToAttachToUpdate(obj : UIWindow)
    {
        var iUpdate = IGameSystem.TryParseToUpdateSystem(obj);
        if(iUpdate != null)
        {
            this.updateUIList.push(iUpdate);
        }
    }

    public OpenUI<T extends UIWindow>(classConstructor : Constructor<T>, uiData : UIData, uILayer : UILayer) : T
    {
        var key = getClassName(classConstructor);
        if(this.uiMap.has(key))
        {
            console.error("open ui more then one! " + key);
            return null;
        }
        else
        {
            var obj = NewClass(classConstructor);
            obj.SetParent(this.uiLayerNodeMap.get(uILayer));
            obj.SetUILayer(uILayer);
            obj.SetData(uiData);
            this.requestUIAssetList.push(obj);
            this.uiMap.set(key, obj);
            return obj as T;
        }
    }

    public UIAssetLoadDoneCallBack(oUI : UIWindow)
    {
        oUI.OnLoadUIMap();
        oUI.OnLoad();

        var sendOnloadImp = IGameSystem.TryParseToSecondLoadSystem(oUI);
        if(sendOnloadImp != null && sendOnloadImp != undefined)
        {
            this.waitDoSecondOnLoadList.push(sendOnloadImp);
        }
        else
        {
            this.TryToAttachToUpdate(oUI);
        }
    }

    public GetOpenUI<T extends UIWindow>(classConstructor : Constructor<T>,) : T
    {
        var key = getClassName(classConstructor);
        if(this.uiMap.has(key))
        {
            return this.uiMap.get(key) as T;
        }
        return null;
    }

    public GetOpenUIByClassName(className : string) : UIWindow
    {
        var key = className;
        if(this.uiMap.has(key))
        {
            return this.uiMap.get(key);
        }
        return null;
    }

    // public GetOrCreateUI<T extends UIWindow>(classConstructor : Constructor<T>, uiData : UIData) : T
    // {
    //     var key = classConstructor.constructor.name;
    //     if(this.uiMap.has(key))
    //     {
    //         return this.uiMap.get(key) as T;
    //     }
    //     return this.OpenUI(classConstructor, uiData);
    // }

    public DestroyUI<T extends UIWindow>(oUI : T) : boolean
    {
        var key = oUI.className;
        if(!this.uiMap.delete(key))
        {
            var sendOnloadImp = IGameSystem.TryParseToSecondLoadSystem(oUI);
            if(sendOnloadImp != null)
            {
                var index = this.curDoSecondOnLoadList.indexOf(sendOnloadImp);
                if(index >= 0)
                {
                    this.curDoSecondOnLoadList.splice(index, 1);
                }

                index = this.waitDoSecondOnLoadList.indexOf(sendOnloadImp);
                if(index >= 0)
                {
                    this.waitDoSecondOnLoadList.splice(index, 1);
                }
            }
            
            var iUpdate = IGameSystem.TryParseToUpdateSystem(oUI);
            if(iUpdate != null)
            {
                var index = this.updateUIList.indexOf(iUpdate);
                if(index >= 0)
                {
                    this.updateUIList.splice(index, 1);
                }
            }
        }

        
        oUI.RecycleAsset();
        oUI.OnDestroy();
        return true;
    }
}

setClassName(UIManager, "UIManager")